package com.thread.threadfirst.studyThread4;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 7、线程池的概念
 * 计算质数（素数）
 * 第一种线程池：FixedThreadPool
 */
public class T_ThreadPool1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //主线程
        long start = System.currentTimeMillis();
        List<Integer> results = getPrime(1, 200000);
        long end = System.currentTimeMillis();
        System.out.println(end - start);

        //使用线程池
        final int CpuCoreNum = 4;  //CPU有几个核就起几个线程，这个电脑是4核的 后来的WorkStealingPool证实了此电脑是8核的。
        ExecutorService service = Executors.newFixedThreadPool(CpuCoreNum);

        MyTask task1 = new MyTask(1, 80000);  //为什么这20万不平均分配呢 每个线程操作5万个数。因为越大的数素数计算时间越长
        MyTask task2 = new MyTask(80001, 130000);
        MyTask task3 = new MyTask(130001, 170000);
        MyTask task4 = new MyTask(170001, 200000);

        Future<List<Integer>> f1 = service.submit(task1);  //submit()中放Callable的任务，所以此对象实现了Callable接口 重写了call()方法。当然了 也可以直接submit(()->{})这样的lambda来函数式编程，但是考虑到写一个类更方便些，因为要传参，而直接lambda是不能给call()方法传参的。
        Future<List<Integer>> f2 = service.submit(task2);
        Future<List<Integer>> f3 = service.submit(task3);
        Future<List<Integer>> f4 = service.submit(task4);

        start = System.currentTimeMillis();  //main主线程依次执行完上面的代码 就走到这里 所以这行可以是开始时间。
        f1.get();  //get()阻塞 等待获取返回结果
        f2.get();
        f3.get();
        f4.get();
        end = System.currentTimeMillis();  //上面的get()阻塞，所以这里才是所有线程执行完任务结束的时间戳。
        System.out.println(end - start);

    }

    static class MyTask implements Callable<List<Integer>> {
        int start, end;

        public MyTask(int start, int end) {
            this.start = start;
            this.end = end;
        }

        @Override
        public List<Integer> call() throws Exception {
            return getPrime(start, end);
        }
    }

    //判断一个数是否是质数
    public static boolean isPrime(int num) {
        for (int i = 2; i <= num / 2; i++) {
            if (num % i == 0) return false;
        }
        return true;
    }

    //判断一个范围的数是否是质数
    public static List<Integer> getPrime(int start, int end) {
        List<Integer> list = new ArrayList<>();
        for (int i = start; i <= end; i++) {
            if (isPrime(i)) list.add(i);
        }
        return list;
    }
}
